﻿using System;
using System.Text;
using System.Drawing;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public static partial class glDRIVE
{
    /// <summary>
    /// double数组转为指针
    /// </summary>
    /// <param name="a"></param>
    /// <returns></returns>
    public static unsafe double* DPTR(double[] a)
    {
        IntPtr a_ptr = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
        return (double*)a_ptr.ToPointer();
    }

    /// <summary>
    /// int数组转为指针
    /// </summary>
    /// <param name="a"></param>
    /// <returns></returns>
    public static unsafe int* IPTR(int[] a)
    {
        IntPtr a_ptr = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
        return (int*)a_ptr.ToPointer();
    }

    /// <summary>
    /// byte数组转为指针
    /// </summary>
    /// <param name="a"></param>
    /// <returns></returns>
    public static unsafe byte* BPTR(byte[] a)
    {
        IntPtr a_ptr = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
        return (byte*)a_ptr.ToPointer();
    }

    /// <summary>
    /// 提取（一维）X数据的最小、最大值
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    public static (double, double) min_max(double[] x)
    {
        double min = float.MaxValue;
        double max = x[0];
        for (int i = 0; i < x.Length; i++)
        {
            if (x[i] > max) max = x[i];
            if (x[i] < min) min = x[i];
        }
        return (min, max);
    }

    /// <summary>
    /// 提取（二维）X数据的最小、最大值
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    public static (double, double) min_max(double[,] x)
    {
        double min = float.MaxValue;
        double max = x[0, 0];
        for (int i = 0; i < x.GetLength(0); i++)
        {
            for (int j = 0; j < x.GetLength(1); j++)
            {
                if (x[i, j] > max) max = x[i, j];
                if (x[i, j] < min) min = x[i, j];
            }
        }
        return (min, max);
    }

    /// <summary>
    /// 绘制数据曲线图表的图片
    /// 转为 img base64 字符串格式显示于 HTML 页面
    /// </summary>
    /// <param name="w">宽度</param>
    /// <param name="h">高度</param>
    /// <param name="x">插值曲线X数据</param>
    /// <param name="y">插值曲线Y数据</param>
    /// <param name="rx">X坐标轴数据</param>
    /// <param name="ry">Y坐标轴数据</param>
    /// <param name="sx">原始X数据</param>
    /// <param name="sy">原始Y数据</param>
    /// <returns></returns>
    public static string html_image(int w, int h, double[] x, double[] y, double[] rx, double[]? ry = null, double[]? sx = null, double[]? sy = null)
    {
        Bitmap bmp = new Bitmap(w, h);

        Graphics g = Graphics.FromImage(bmp);
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        g.Clear(Color.White);

        #region 估算绘图区域（上下左右留空）
        int padding = (int)(Math.Min(w, h) * 0.05);
        int tail = padding / 2;
        int padding_top = padding;
        int padding_right = padding;
        Font ft = new Font("Arial", h / 90.0F);
        SizeF fz = g.MeasureString("0000", ft);
        int padding_left = (int)fz.Width + padding + tail;
        int padding_bottom = (int)fz.Height + padding + tail;
        double w1 = w - padding_left - padding_right;
        double h1 = h - padding_top - padding_bottom;
        double scale_x = w1 / (rx[rx.Length - 1] - rx[0]);
        //(double y_min, double y_max) = min_max(y);
        double y_min = ry[0];
        double y_max = ry[ry.Length - 1];
        double scale_y = h1 * 0.9 / (y_max - y_min);
        #endregion

        // 绘制外围矩形
        Pen pb = new Pen(Color.Black, 2.0F);
        g.DrawRectangle(
            pb,
            new RectangleF(padding_left, padding_top, (float)w1, (float)h1)
        );

        // 坐标变换函数
        float xx(double v)
        {
            return (float)(padding_left + (v - rx[0]) * scale_x);
        }
        float yy(double v)
        {
            return (float)(padding_top + (h1 - (v - y_min) * scale_y));
        }

        Pen pg = new Pen(Color.LightGray, 0.5F);
        SolidBrush sb = new SolidBrush(Color.DarkBlue);

        #region 绘制 X 轴线
        for (int i = 0; i < rx.Length; i++)
        {
            float x1 = xx(rx[i]);
            float y1 = (float)(padding_top + h1);

            // 居中！
            SizeF kz = g.MeasureString(rx[i] + "", ft);
            g.DrawString(
                rx[i] + "",
                ft,
                sb,
                new PointF(x1 - kz.Width / 2.0F, y1 + tail)
            );

            // 纵向
            g.DrawLine(
                pg,
                new PointF(x1, padding_top),
                new PointF(x1, padding_top + (float)h1)
            );

            // 短线！
            g.DrawLine(
                pb,
                new PointF(x1, padding_top + (float)h1),
                new PointF(x1, padding_top + (float)(h1 + tail / 2.0))
            );
        }
        #endregion

        #region 绘制 Y 轴线
        for (int i = 0; i < ry.Length; i++)
        {
            float x1 = padding_left - tail;
            float y1 = yy(ry[i]);

            // 上下居中！
            SizeF kz = g.MeasureString(ry[i] + "", ft);
            x1 -= kz.Width - 2;
            g.DrawString(
                ry[i] + "",
                ft,
                sb,
                new PointF(x1, y1 - kz.Height / 2.0F)
            );

            // 横线
            g.DrawLine(
                pg,
                new PointF(padding_left, y1),
                new PointF(padding_left + (float)w1, y1)
            );

            // 短线！
            g.DrawLine(
                pb,
                new PointF(padding_left, y1),
                new PointF(padding_left - tail / 2, y1)
            );
        }
        #endregion

        #region 绘制曲线
        Pen pl = new Pen(Color.OrangeRed, 1.5F);
        PointF[] points = new PointF[x.Length];
        for (int i = 0; i < x.Length; i++)
        {
            float x1 = xx(x[i]);
            float y1 = yy(y[i]);
            points[i] = new PointF(x1, y1);
        }
        g.DrawLines(pl, points);
        #endregion

        #region 绘制标记！
        SolidBrush mb = new SolidBrush(Color.Gray);
        for (int i = 0; i < sx.Length; i++)
        {
            float x1 = xx(sx[i]);
            float y1 = yy(sy[i]);
            g.FillEllipse(mb, new RectangleF(x1 - tail / 2, y1 - tail / 2, tail, tail));
        }
        #endregion

        return "<img border='1' src='data:image/png;base64," + BitmapHelper.BitmapToBase64String(bmp) + "'><br><br>";
    }
}

